#ifndef _GATEWAY_ACCEPTOR_HPP_
#define _GATEWAY_ACCEPTOR_HPP_

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include "gateway_stream.h"
#include "gateway_network_event.h"

class gateway_acceptor {
public:
	gateway_acceptor() 
	: _acceptor_event(NULL)
	, _work(_io_service)
	, _acceptor(NULL) {
		init();
	}

	~gateway_acceptor() {
		clean();
	}

	void set_event_handle(gateway_acceptor_event* acceptor_event) {
		_acceptor_event = acceptor_event;
	}

	bool start(const char* host, unsigned short port){

		boost::asio::ip::address addr = boost::asio::ip::address::from_string(host);
		boost::asio::ip::tcp::endpoint ep(addr, port);

		try{
			_acceptor = new boost::asio::ip::tcp::acceptor(_io_service, ep);
		}
		catch(boost::system::system_error& ec) {
			std::cout << ec.what() << std::endl;
			return false;
		}

		gateway_stream_ptr stream_ptr(new gateway_stream(_io_service));
		_acceptor->async_accept(stream_ptr->get_socket(), boost::bind(&gateway_acceptor::handle_accept,
			this, stream_ptr, boost::asio::placeholders::error));

		return true;
	}

	void stop(){
		if (_acceptor) {
			_acceptor->close();
			delete _acceptor;
			_acceptor = NULL;
		}
	}

private:

	void init() {
		size_t cpu_num = boost::thread::hardware_concurrency();
		unsigned int _threads_num = cpu_num * 2 + 2;
		for (unsigned int i = 0; i < _threads_num; i++) {
			_thread_group.create_thread(boost::bind(&boost::asio::io_service::run, &_io_service));
		}
	}

	void clean(){
		_io_service.stop();
		_thread_group.join_all();
	}

	void handle_accept(gateway_stream_ptr stream_ptr,const boost::system::error_code& error){
		if (!error){
			if (_acceptor_event) {
				if (_acceptor_event->acceptor_notify(stream_ptr) < 0) {
					boost::system::error_code ec;
					stream_ptr->get_socket().close(ec);
				}
				else {
					stream_ptr->open();
				}
			}
			else {
				stream_ptr->open();
			}

			stream_ptr.reset(new gateway_stream(_io_service));
			_acceptor->async_accept(stream_ptr->get_socket(), boost::bind(&gateway_acceptor::handle_accept,
				this, stream_ptr, boost::asio::placeholders::error));
		}
	}

private:
	boost::thread_group _thread_group;
	boost::asio::io_service _io_service;
	boost::asio::io_service::work _work;
	gateway_acceptor_event* _acceptor_event;
	boost::asio::ip::tcp::acceptor* _acceptor;
};

#endif